/**
 * CollisionDetector - 碰撞检测系统
 * 支持矩形碰撞检测和空间分区优化
 */

import { Entity } from './Entity'
import type { Vector2D } from './GameEngine'

export interface CollisionInfo {
  entityA: Entity
  entityB: Entity
  overlap: Vector2D
  normal: Vector2D
}

export interface SpatialGrid {
  cellSize: number
  width: number
  height: number
  cells: Map<string, Set<Entity>>
}

export interface CollisionDetectorOptions {
  enableSpatialPartitioning?: boolean
  spatialGridCellSize?: number
  worldWidth?: number
  worldHeight?: number
}

export class CollisionDetector {
  private enableSpatialPartitioning: boolean
  private spatialGrid: SpatialGrid | null = null
  private collisionCallbacks: Map<string, (collision: CollisionInfo) => void> = new Map()

  constructor(options: CollisionDetectorOptions = {}) {
    this.enableSpatialPartitioning = options.enableSpatialPartitioning || false
    
    if (this.enableSpatialPartitioning) {
      this.initializeSpatialGrid(
        options.spatialGridCellSize || 64,
        options.worldWidth || 1600,
        options.worldHeight || 800
      )
    }
  }

  /**
   * 初始化空间分区网格
   */
  private initializeSpatialGrid(cellSize: number, worldWidth: number, worldHeight: number): void {
    this.spatialGrid = {
      cellSize,
      width: Math.ceil(worldWidth / cellSize),
      height: Math.ceil(worldHeight / cellSize),
      cells: new Map()
    }
  }

  /**
   * 检查两个矩形是否碰撞
   */
  static checkRectangleCollision(
    x1: number, y1: number, w1: number, h1: number,
    x2: number, y2: number, w2: number, h2: number
  ): boolean {
    return (
      x1 < x2 + w2 &&
      x1 + w1 > x2 &&
      y1 < y2 + h2 &&
      y1 + h1 > y2
    )
  }

  /**
   * 检查两个实体是否碰撞
   */
  static checkEntityCollision(entityA: Entity, entityB: Entity): boolean {
    return CollisionDetector.checkRectangleCollision(
      entityA.x, entityA.y, entityA.width, entityA.height,
      entityB.x, entityB.y, entityB.width, entityB.height
    )
  }

  /**
   * 计算两个矩形的碰撞信息
   */
  static getCollisionInfo(entityA: Entity, entityB: Entity): CollisionInfo | null {
    if (!CollisionDetector.checkEntityCollision(entityA, entityB)) {
      return null
    }

    // 计算重叠区域
    const overlapX = Math.min(entityA.x + entityA.width, entityB.x + entityB.width) - 
                     Math.max(entityA.x, entityB.x)
    const overlapY = Math.min(entityA.y + entityA.height, entityB.y + entityB.height) - 
                     Math.max(entityA.y, entityB.y)

    // 计算碰撞法向量（从A指向B的最短分离方向）
    let normalX = 0
    let normalY = 0

    if (overlapX < overlapY) {
      // 水平分离
      normalX = entityA.x < entityB.x ? -1 : 1
    } else {
      // 垂直分离
      normalY = entityA.y < entityB.y ? -1 : 1
    }

    return {
      entityA,
      entityB,
      overlap: { x: overlapX, y: overlapY },
      normal: { x: normalX, y: normalY }
    }
  }

  /**
   * 检测所有实体之间的碰撞
   */
  detectCollisions(entities: Entity[]): CollisionInfo[] {
    const collisions: CollisionInfo[] = []

    if (this.enableSpatialPartitioning && this.spatialGrid) {
      return this.detectCollisionsWithSpatialPartitioning(entities)
    }

    // 暴力检测法 - O(n²)
    for (let i = 0; i < entities.length; i++) {
      for (let j = i + 1; j < entities.length; j++) {
        const entityA = entities[i]
        const entityB = entities[j]

        if (!entityA.active || !entityB.active) continue

        const collision = CollisionDetector.getCollisionInfo(entityA, entityB)
        if (collision) {
          collisions.push(collision)
          this.handleCollision(collision)
        }
      }
    }

    return collisions
  }

  /**
   * 使用空间分区进行碰撞检测
   */
  private detectCollisionsWithSpatialPartitioning(entities: Entity[]): CollisionInfo[] {
    if (!this.spatialGrid) return []

    const collisions: CollisionInfo[] = []
    
    // 清空网格
    this.spatialGrid.cells.clear()

    // 将实体分配到网格单元
    for (const entity of entities) {
      if (!entity.active) continue
      
      const cells = this.getEntityCells(entity)
      for (const cellKey of cells) {
        if (!this.spatialGrid.cells.has(cellKey)) {
          this.spatialGrid.cells.set(cellKey, new Set())
        }
        this.spatialGrid.cells.get(cellKey)!.add(entity)
      }
    }

    // 检查每个网格单元内的碰撞
    const checkedPairs = new Set<string>()
    
    for (const [, cellEntities] of this.spatialGrid.cells) {
      const entitiesArray = Array.from(cellEntities)
      
      for (let i = 0; i < entitiesArray.length; i++) {
        for (let j = i + 1; j < entitiesArray.length; j++) {
          const entityA = entitiesArray[i]
          const entityB = entitiesArray[j]
          
          // 避免重复检查同一对实体
          const pairKey = this.getPairKey(entityA.id, entityB.id)
          if (checkedPairs.has(pairKey)) continue
          checkedPairs.add(pairKey)

          const collision = CollisionDetector.getCollisionInfo(entityA, entityB)
          if (collision) {
            collisions.push(collision)
            this.handleCollision(collision)
          }
        }
      }
    }

    return collisions
  }

  /**
   * 获取实体所占据的网格单元
   */
  private getEntityCells(entity: Entity): string[] {
    if (!this.spatialGrid) return []

    const cells: string[] = []
    const cellSize = this.spatialGrid.cellSize

    const startX = Math.floor(entity.x / cellSize)
    const endX = Math.floor((entity.x + entity.width) / cellSize)
    const startY = Math.floor(entity.y / cellSize)
    const endY = Math.floor((entity.y + entity.height) / cellSize)

    for (let x = startX; x <= endX; x++) {
      for (let y = startY; y <= endY; y++) {
        if (x >= 0 && x < this.spatialGrid.width && y >= 0 && y < this.spatialGrid.height) {
          cells.push(`${x},${y}`)
        }
      }
    }

    return cells
  }

  /**
   * 生成实体对的唯一键
   */
  private getPairKey(idA: string, idB: string): string {
    return idA < idB ? `${idA}-${idB}` : `${idB}-${idA}`
  }

  /**
   * 处理碰撞
   */
  private handleCollision(collision: CollisionInfo): void {
    const callbackKey = this.getCollisionCallbackKey(collision.entityA.type, collision.entityB.type)
    const callback = this.collisionCallbacks.get(callbackKey)
    
    if (callback) {
      callback(collision)
    }
  }

  /**
   * 注册碰撞回调
   */
  registerCollisionCallback(
    typeA: string, 
    typeB: string, 
    callback: (collision: CollisionInfo) => void
  ): void {
    const key = this.getCollisionCallbackKey(typeA, typeB)
    this.collisionCallbacks.set(key, callback)
  }

  /**
   * 移除碰撞回调
   */
  unregisterCollisionCallback(typeA: string, typeB: string): void {
    const key = this.getCollisionCallbackKey(typeA, typeB)
    this.collisionCallbacks.delete(key)
  }

  /**
   * 生成碰撞回调键
   */
  private getCollisionCallbackKey(typeA: string, typeB: string): string {
    return typeA < typeB ? `${typeA}-${typeB}` : `${typeB}-${typeA}`
  }

  /**
   * 检查点是否在矩形内
   */
  static isPointInRectangle(
    pointX: number, 
    pointY: number, 
    rectX: number, 
    rectY: number, 
    rectWidth: number, 
    rectHeight: number
  ): boolean {
    return (
      pointX >= rectX &&
      pointX <= rectX + rectWidth &&
      pointY >= rectY &&
      pointY <= rectY + rectHeight
    )
  }

  /**
   * 检查点是否在实体内
   */
  static isPointInEntity(pointX: number, pointY: number, entity: Entity): boolean {
    return CollisionDetector.isPointInRectangle(
      pointX, pointY, entity.x, entity.y, entity.width, entity.height
    )
  }

  /**
   * 计算两点之间的距离
   */
  static getDistance(x1: number, y1: number, x2: number, y2: number): number {
    const dx = x2 - x1
    const dy = y2 - y1
    return Math.sqrt(dx * dx + dy * dy)
  }

  /**
   * 检查圆形碰撞
   */
  static checkCircleCollision(
    x1: number, y1: number, r1: number,
    x2: number, y2: number, r2: number
  ): boolean {
    const distance = CollisionDetector.getDistance(x1, y1, x2, y2)
    return distance <= r1 + r2
  }

  /**
   * 解决碰撞（简单的位置分离）
   */
  static resolveCollision(collision: CollisionInfo): void {
    const { entityA, entityB, overlap, normal } = collision

    // 计算分离距离
    const separationX = overlap.x * normal.x * 0.5
    const separationY = overlap.y * normal.y * 0.5

    // 分离实体
    entityA.x -= separationX
    entityA.y -= separationY
    entityB.x += separationX
    entityB.y += separationY
  }

  /**
   * 获取性能统计
   */
  getPerformanceStats(): {
    spatialPartitioningEnabled: boolean
    gridCellCount: number
    activeGridCells: number
  } {
    return {
      spatialPartitioningEnabled: this.enableSpatialPartitioning,
      gridCellCount: this.spatialGrid ? this.spatialGrid.width * this.spatialGrid.height : 0,
      activeGridCells: this.spatialGrid ? this.spatialGrid.cells.size : 0
    }
  }

  /**
   * 清理资源
   */
  cleanup(): void {
    this.collisionCallbacks.clear()
    if (this.spatialGrid) {
      this.spatialGrid.cells.clear()
    }
  }
}